﻿using System.IO.Compression;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace WinFormsGenDLL
{
    public class Common
    {

        public static void SaveFile(MemoryStream ms, string fileName)
        {
            SaveFile(ms.ToArray(), fileName);
        }

        public static void SaveFile(byte[] bytes, string fileName)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                fs.Write(bytes, 0, bytes.Length);
                fs.Close();
            }
        }

        /// <summary>
        /// 获取异常对象
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static Exception GetInnerException(Exception ex)
        {
            if (ex.InnerException != null)
            {
                return GetInnerException(ex.InnerException);
            }
            return ex;
        }
        public static MemoryStream GetHttpFileStream(string url)
        {
            HttpClient client = new HttpClient();
            client.Timeout = new TimeSpan(0, 20, 0);
            using (Stream stream = client.GetStreamAsync(url).Result)
            {
                MemoryStream memoryStream = new MemoryStream();

                int count = 0;
                byte[] buffer = new byte[1024];
                while ((count = stream.Read(buffer, 0, 1024)) > 0)
                {
                    memoryStream.Write(buffer, 0, count);
                }
                memoryStream.Position = 0;

                return memoryStream;
            }
        }

 
        private static void GetFileList(Dictionary<string, object> dict, string rootPath, string path)
        {
            foreach (string f in Directory.GetFiles(path))
            {
                dict.Add(f.Substring(rootPath.Length), File.ReadAllBytes(f));
            }

            foreach (string f in Directory.GetDirectories(path))
            {
                GetFileList(dict, rootPath, f);
            }
        }

        public static void Compress(string dirPath, string fileName)
        {
            Dictionary<string, object> dict = new Dictionary<string, object>();
            GetFileList(dict, dirPath, dirPath);

            #pragma warning disable SYSLIB0011
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, dict);
                ms.Position = 0;
                CreateCompressFile(ms, fileName);
            }
        }

        private static void CreateCompressFile(Stream source, string fileName)
        {
            using (Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                using (GZipStream output = new GZipStream(stream, CompressionMode.Compress))
                {
                    byte[] bytes = new byte[4096];
                    int n = 0;
                    while ((n = source.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        output.Write(bytes, 0, n);
                    }
                }
            }
        }

        public static byte[] CompressBytes(byte[] bs)
        {
            MemoryStream source = new MemoryStream(bs);
            MemoryStream ms = new MemoryStream();
            using (GZipStream output = new GZipStream(ms, CompressionMode.Compress))
            {
                byte[] bytes = new byte[4096];
                int n = 0;
                while ((n = source.Read(bytes, 0, bytes.Length)) != 0)
                {
                    output.Write(bytes, 0, n);
                }
            }
            return ms.ToArray();
        }

        public static byte[] DeCompressBytes(byte[] bs)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream input = new GZipStream(new MemoryStream(bs), CompressionMode.Decompress, true))
                {
                    byte[] bytes = new byte[4096];
                    int n = 0;
                    while ((n = input.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        ms.Write(bytes, 0, n);
                    }
                }
                ms.Flush();
                ms.Position = 0;
                return ms.ToArray();
            }
        }

        public static void DeCompress(Stream source, string dirPath)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream input = new GZipStream(source, CompressionMode.Decompress, true))
                {
                    byte[] bytes = new byte[4096];
                    int n = 0;
                    while ((n = input.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        ms.Write(bytes, 0, n);
                    }
                }
                ms.Flush();
                ms.Position = 0;
                DeSerializeFiles(ms, dirPath);
            }
        }

        public static void DeCompress(byte[] source, string dirPath)
        {
            DeCompress(new MemoryStream(source), dirPath);
        }

        public static void DeCompress(string fileName, string dirPath)
        {
            using (Stream source = File.OpenRead(fileName))
            {
                DeCompress(source, dirPath);
            }
        }

        private static void DeSerializeFiles(Stream stream, string dirPath)
        {
            BinaryFormatter bf = new BinaryFormatter();
            Dictionary<string, object> dict = (Dictionary<string, object>)bf.Deserialize(stream);

            string fileName = string.Empty;
            string dir = string.Empty;

            foreach (var kvp in dict)
            {
                fileName = string.Concat(dirPath, kvp.Key);
                dir = Path.GetDirectoryName(fileName);

                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

                byte[] bytes = (byte[])kvp.Value;
                using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                {
                    fs.Write(bytes, 0, bytes.Length);
                    fs.Close();
                }
            }
        }
    }
}
